////////////////////////////////////////////////////////////////////////////////
// Filename: bitmapclass.cpp
////////////////////////////////////////////////////////////////////////////////
#include "bitmapclass.h"

//-------------------------------------------------------------------------------------------------------------------
BitmapClass::BitmapClass() : m_vertexBuffer(0), m_indexBuffer(0), m_Texture(0)
{ }

//-------------------------------------------------------------------------------------------------------------------
BitmapClass::BitmapClass(const BitmapClass& rhs)
{ }

//-------------------------------------------------------------------------------------------------------------------
BitmapClass::~BitmapClass()
{ }

//-------------------------------------------------------------------------------------------------------------------
bool BitmapClass::Initialize(ID3D11Device* device, int screenWidth, int screenHeight,
	WCHAR* textureFilename, int bitmapWidth, int bitmapHeight)
{
	bool result;
	
	m_screenWidth  = screenWidth;		// Store the screen size.
	m_screenHeight = screenHeight;

	m_bitmapWidth  = bitmapWidth;		// Store the size in pixels that this bitmap should be rendered at.
	m_bitmapHeight = bitmapHeight;
	
	m_previousPosX = -1;				// Initialize the previous rendering position to negative one.
	m_previousPosY = -1;
	
	result = InitializeBuffers(device);	// Initialize the vertex and index buffers.
	if (!result)
		return false;
	
	result = LoadTexture(device, textureFilename); // Load the texture for this model.
	if (!result)
		return false;

	return true;
}

//-------------------------------------------------------------------------------------------------------------------
void BitmapClass::Shutdown()
{
	ReleaseTexture();		// Release the model textures.
	ShutdownBuffers();		// Shutdown the vertex and index buffers.

	return;
}

//-------------------------------------------------------------------------------------------------------------------
bool BitmapClass::Render(ID3D11DeviceContext* deviceContext)
{
	//bool result;

	// Re-build the dynamic vertex buffer for rendering to possibly a different location on screen.
	//result = UpdateBuffers(deviceContext, positionX, positionY);
	//if (!result)
	//	return false;

	RenderBuffers(deviceContext);		// Put the vertex and index buffers on the graphics pipeline.

	return true;
}

//-------------------------------------------------------------------------------------------------------------------
bool BitmapClass::InitializeBuffers(ID3D11Device* device)
{
	VertexType2D*				vertices;
	unsigned long*				indices;
	D3D11_BUFFER_DESC			vertexBufferDesc, indexBufferDesc;
	D3D11_SUBRESOURCE_DATA		vertexData, indexData;
	HRESULT						result;
	int							i;
	
	m_vertexCount = 6;				// Set the number of vertices in the vertex array.
	m_indexCount = m_vertexCount;	// Set the number of indices in the index array.
	
	vertices = new VertexType2D[m_vertexCount];		// Create the vertex array.
	if (!vertices)
		return false;
	
	indices = new unsigned long[m_indexCount];		// Create the index array.
	if (!indices)
		return false;
	
	memset(vertices, 0, (sizeof(VertexType2D) * m_vertexCount)); // Initialize vertex array to zero.
	
	for (i=0; i<m_indexCount; ++i)	// Load the index array with data.
		indices[i] = i;

	// Description of the dynamic vertex buffer.
	vertexBufferDesc.Usage = D3D11_USAGE_DYNAMIC;
	vertexBufferDesc.ByteWidth = sizeof(VertexType2D) * m_vertexCount;
	vertexBufferDesc.BindFlags = D3D11_BIND_VERTEX_BUFFER;
	vertexBufferDesc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
	vertexBufferDesc.MiscFlags = 0;
	vertexBufferDesc.StructureByteStride = 0;
	
	vertexData.pSysMem = vertices;		// Vertex data.
	vertexData.SysMemPitch = 0;
	vertexData.SysMemSlicePitch = 0;
	
	result = device->CreateBuffer(&vertexBufferDesc, &vertexData, &m_vertexBuffer);	 // Now create the vertex buffer.
	if (FAILED(result))
		return false;

	// Description on the static index buffer.
	indexBufferDesc.Usage = D3D11_USAGE_DEFAULT;
	indexBufferDesc.ByteWidth = sizeof(unsigned long) * m_indexCount;
	indexBufferDesc.BindFlags = D3D11_BIND_INDEX_BUFFER;
	indexBufferDesc.CPUAccessFlags = 0;
	indexBufferDesc.MiscFlags = 0;
	indexBufferDesc.StructureByteStride = 0;
	
	indexData.pSysMem = indices;	// Index data.
	indexData.SysMemPitch = 0;
	indexData.SysMemSlicePitch = 0;
	
	result = device->CreateBuffer(&indexBufferDesc, &indexData, &m_indexBuffer);	// Create the index buffer.
	if (FAILED(result))
		return false;
	
	delete [] vertices;		// Release vertex array.
	vertices = nullptr;

	delete [] indices;		// Release index array.
	indices = nullptr;

	return true;
}

//-------------------------------------------------------------------------------------------------------------------
bool BitmapClass::UpdateBuffers(ID3D11DeviceContext* deviceContext, int positionX, int positionY)
{
	float						left, right, top, bottom;
	VertexType2D* 				vertices;
	D3D11_MAPPED_SUBRESOURCE	mappedResource;
	VertexType2D*				verticesPtr;
	HRESULT						result;


	// Check if bitmap position has changed.
	if((positionX == m_previousPosX) && (positionY == m_previousPosY))
	{
		return true;
	}
	
	m_previousPosX = positionX;		// Update the position it is being rendered to.
	m_previousPosY = positionY;
	
	left = (float)((m_screenWidth / 2) * -1) + (float)positionX; // Screen coordinate of the left side of the bitmap.
	right = left + (float)m_bitmapWidth;						 // Screen coordinate of the right side of the bitmap.
	top = (float)(m_screenHeight / 2) - (float)positionY;		 // Screen coordinate of the top of the bitmap.
	bottom = top - (float)m_bitmapHeight;						 // Screen coordinate of the bottom of the bitmap.
	
	vertices = new VertexType2D[m_vertexCount];		// Create the vertex array.
	if(!vertices)
		return false;

	// Load the vertex array with data.
	// First triangle.
	vertices[0].position = D3DXVECTOR3(left, top, 0.0f);		// Top left.
	vertices[0].texture  = D3DXVECTOR2(0.0f, 0.0f);

	vertices[1].position = D3DXVECTOR3(right, bottom, 0.0f);	// Bottom right.
	vertices[1].texture  = D3DXVECTOR2(1.0f, 1.0f);

	vertices[2].position = D3DXVECTOR3(left, bottom, 0.0f);		// Bottom left.
	vertices[2].texture  = D3DXVECTOR2(0.0f, 1.0f);

	// Second triangle.
	vertices[3].position = D3DXVECTOR3(left, top, 0.0f);		// Top left.
	vertices[3].texture  = D3DXVECTOR2(0.0f, 0.0f);

	vertices[4].position = D3DXVECTOR3(right, top, 0.0f);		// Top right.
	vertices[4].texture  = D3DXVECTOR2(1.0f, 0.0f);

	vertices[5].position = D3DXVECTOR3(right, bottom, 0.0f);	// Bottom right.
	vertices[5].texture  = D3DXVECTOR2(1.0f, 1.0f);

	// Lock the vertex buffer so it can be written to.
	result = deviceContext->Map(m_vertexBuffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &mappedResource);
	if(FAILED(result))
		return false;
	
	verticesPtr = (VertexType2D*)mappedResource.pData;	 // Get a pointer to the data in the vertex buffer.
	
	memcpy(verticesPtr, (void*)vertices, (sizeof(VertexType2D) * m_vertexCount)); // Copy data into the vertex buffer.
	
	deviceContext->Unmap(m_vertexBuffer, 0);	// Unlock the vertex buffer.
	
	delete [] vertices;		// Release the vertex array.
	vertices = 0;

	return true;
}

//-------------------------------------------------------------------------------------------------------------------
void BitmapClass::RenderBuffers(ID3D11DeviceContext* deviceContext)
{
	unsigned int stride;
	unsigned int offset;

	// Set the vertex buffer stride and offset.
	stride = sizeof(VertexType2D);
	offset = 0;

	deviceContext->IASetVertexBuffers(0, 1, &m_vertexBuffer, &stride, &offset);		// Activate vertex buffer.
	deviceContext->IASetIndexBuffer(m_indexBuffer, DXGI_FORMAT_R32_UINT, 0);		// Activate index buffer.
	deviceContext->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);	// Set primitive topology.
}

//-------------------------------------------------------------------------------------------------------------------
bool BitmapClass::LoadTexture(ID3D11Device* device, WCHAR* filename)
{
	bool result;
	
	m_Texture = new TextureClass;	// Create the texture object.
	if (!m_Texture)
		return false;
	
	result = m_Texture->Initialize(device, filename);	// Initialize the texture object.
	if (!result)
		return false;

	return true;
}

//-------------------------------------------------------------------------------------------------------------------
void BitmapClass::ReleaseTexture()
{
	if (m_Texture)		// Release the texture object.
	{
		m_Texture->Shutdown();
		delete m_Texture;
		m_Texture = nullptr;
	}

	return;
}

//-------------------------------------------------------------------------------------------------------------------
void BitmapClass::ShutdownBuffers()
{
	if (m_indexBuffer)		// Release the index buffer.
	{
		m_indexBuffer->Release();
		m_indexBuffer = nullptr;
	}
	
	if (m_vertexBuffer)		// Release the vertex buffer.
	{
		m_vertexBuffer->Release();
		m_vertexBuffer = nullptr;
	}

	return;
}

//-------------------------------------------------------------------------------------------------------------------
int BitmapClass::GetIndexCount()
{
	return m_indexCount;
}

//-------------------------------------------------------------------------------------------------------------------
ID3D11ShaderResourceView* BitmapClass::GetTexture()
{
	return m_Texture->GetTexture();
}